/* eslint-disable jsx-a11y/label-has-associated-control */
/* eslint-disable no-restricted-syntax */
/* eslint-disable react/no-string-refs */
import { Component } from 'react';
import PropTypes from 'prop-types';
import wysiwyg from './wysiwyg.min';

import './Editor.less';
import './fontawesome/less/font-awesome.less';

const foreColor = {
    command: 'forecolor',
    values: ['#3388ff', '#06bc07', '#ffb123', '#ab2212', '#680000', '#586b95', '#000000'],
};
const fontSize = {
    command: 'fontSize',
    values: [1, 2, 3, 4, 5, 6],
    valueAlias: ['12px', '14px', '16px', '18px', '20px', '22px'],
};
// const fontName = {
//     command: 'fontName',
//     values: ['宋体, SimSun', '微软雅黑, "Microsoft YaHei"', '魏碑-简', '冬青黑体'],
// };

const preventUnload = e => {
    console.log(e);
    const message = '少侠留步，有内容没保存!';
    if (e) {
        e.returnValue = message;
    }
    return message;
};

export default class Editor extends Component {
    static defaultProps = {
        content: '',
        style: {},
        onChange: () => {}
    };

    constructor() {
        super();
        this.exec = this._exec.bind(this);
        this.insertLink = this._insertLink.bind(this);
        this.handleInputChange = this._handleInputChange.bind(this);
        this.handleBlur = this._handleBlur.bind(this);
        this.handleInput = this._handleInput.bind(this);
        this.hideTools = this._hideTools.bind(this);
        this.toggle = this._toggle.bind(this);
        this.toggleLink = this._toggleLink.bind(this);
        this.toggleFont = this._toggleFont.bind(this);
        this.formatFontSize = this._formatFontSize.bind(this);
        this.attachToElement = this._attachToElement.bind(this);
        this.replaceFontSizeAbsoluteToPixel = this._replaceFontSizeAbsoluteToPixel.bind(this);
        document.execCommand('styleWithCSS', false);
    }

    state = {
        linkVisibility: false,
        linkValue: '',
        linkText: '',
        fontVisibility: false,
        editorSelection: null,
    };

    componentDidMount() {
        const editor = this.refs.editor;
        this.editor = wysiwyg({
            element: editor,
            onSelection: () => {
                this.hideTools();
            },
            onPlaceholder: () => {},
        });
        this.moveCursorToEnd();
        editor.addEventListener('input', () => {
            this.replaceFontSizeAbsoluteToPixel();
            this.handleInput();
        });
        editor.addEventListener('paste', e => {
            e.preventDefault();
            const range = document.getSelection().getRangeAt(0);
            const span = document.createElement('span');
            span.innerHTML = e.clipboardData.getData('text');
            range.insertNode(span);
            this.handleInput();
        });
        window.addEventListener('resize', () => {
            setTimeout(() => this.attachToElement(this.refs.fontSelect, this.refs.fontIcon), 300);
        });
        window.addEventListener('popstate', preventUnload);
        window.addEventListener('beforeunload', preventUnload);
        window.addEventListener('keydown', this.preventBackspace);

        setTimeout(() => this.attachToElement(this.refs.fontSelect, this.refs.fontIcon), 300);
    }

    componentWillUnmount() {
        window.removeEventListener('popstate', preventUnload);
        window.removeEventListener('beforeunload', preventUnload);
        window.removeEventListener('keydown', this.preventBackspace);
    }

    preventBackspace(e) {
        console.log(e);
        if (e.keyCode === 8 && !(e.target.isContentEditable || e.target.nodeName === 'INPUT')) {
            console.log('prevent');
            e.preventDefault();
        }
    }

    _attachToElement(src, target) {
        console.log(target.getClientRects());
        const targetRect = target.getClientRects()[0];
        const rootRect = this.refs.root.getClientRects()[0];
        console.log(targetRect);
        src.style.top = `${targetRect.top - targetRect.height + 10}px`;
        src.style.left = `${targetRect.left - rootRect.left - 1}px`;
    }

    moveCursorToEnd() {
        const selection = document.getSelection();
        const range = document.createRange();
        selection.removeAllRanges();
        const editor = this.refs.editor;
        const offset = editor.childNodes.length;
        range.setStart(editor, offset);
        range.setEnd(editor, offset);
        selection.addRange(range);
    }

    _exec(command, value) {
        return () => {
            if (!this.editor) return;
            this.editor[command](value);
        };
    }

    _insertLink() {
        const { linkValue, linkText, editorSelection } = this.state;
        if (!linkValue.length) {
            return;
        }
        const selection = document.getSelection();
        const newRange = document.createRange();
        selection.removeAllRanges();
        newRange.setStart(editorSelection.anchorNode, editorSelection.anchorOffset);
        newRange.setEnd(editorSelection.focusNode, editorSelection.focusOffset);

        const anchor = document.createElement('a');
        anchor.href = linkValue;
        anchor.innerHTML = linkText || linkValue;
        selection.addRange(newRange);
        newRange.deleteContents();
        newRange.insertNode(anchor);

        // 操作selection不会触发input事件
        this.handleInput();

        this.hideTools();
    }

    _handleInputChange(name) {
        return e => {
            this.setState({ [name]: e.target.value });
        };
    }

    _hideTools() {
        this.setState({
            linkVisibility: false,
            fontVisibility: false,
        });
    }

    _toggle(name) {
        if (!this.state[name]) {
            this.hideTools();
        }
        this.setState({ [name]: !this.state[name] });
    }

    _toggleLink(e) {
        e.stopPropagation();
        if (!this.state.linkVisibility) {
            this.setState({ linkText: window.getSelection().toString() });
        }
        this.toggle('linkVisibility');
    }

    _toggleFont(e) {
        e.stopPropagation();
        this.toggle('fontVisibility');
    }

    _formatFontSize(v) {
        return () => {
            this.exec('fontSize', v)();
            this.replaceFontSizeAbsoluteToPixel();
        };
    }

    _replaceFontSizeAbsoluteToPixel() {
        const absolutes = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];
        const pixels = ['10px', '12px', '14px', '16px', '18px', '20px', '22px'];
        const styleNodes = this.refs.editor.querySelectorAll('[style]');
        // eslint-disable-next-line no-unused-vars
        for (const i in styleNodes) {
            if (styleNodes[i].style) {
                const index = absolutes.indexOf(styleNodes[i].style.fontSize);
                // eslint-disable-next-line no-bitwise
                if (~index) {
                    styleNodes[i].style.fontSize = pixels[index];
                }
            }
        }
    }

    _handleBlur() {
        const {
            anchorNode, anchorOffset, focusNode, focusOffset, isCollapsed, rangeCount
        } = document.getSelection();
        this.setState({
            editorSelection: {
                anchorNode, anchorOffset, focusNode, focusOffset, isCollapsed, rangeCount
            },
        });
    }

    _handleInput() {
        this.props.onChange && this.props.onChange(this.editor.getHTML());
    }

    render() {
        const { state, props } = this;

        return (
            <div ref="root" className="moduleCommandEditor" style={props.style}>
                <div className="toolBar" onClick={this.hideTools}>
                    <button onClick={this.exec('bold')}>
                        <i className="fa fa-fw fa-bold " />
                    </button>
                    <button onClick={this.exec('italic')}>
                        <i className="fa fa-fw fa-italic" />
                    </button>
                    <button onClick={this.exec('underline')}>
                        <i className="fa fa-fw fa-underline" />
                    </button>
                    <button onClick={this.toggleFont} ref="fontIcon">
                        <i className="fa fa-fw fa-font" />
                    </button>
                    <button onClick={this.toggleLink}>
                        <i className="fa fa-fw fa-link" />
                    </button>
                    {/* fontName.values.map((v) => {
                        return <button key={`${fontName.command}-${v}`} onClick={this.exec(fontName.command, v)}><i className="fa fa-fw fa-font" />{v}</button>
                    }) */}
                    <button onClick={this.exec('removeFormat')}>
                        <i className="fa fa-fw fa-eraser" />
                    </button>
                    {foreColor.values.map(v => (
                        <button key={`${foreColor.command}-${v}`} onClick={this.exec(foreColor.command, v)}>
                            <i className="fa fa-fw fa-square" style={{ color: v }} />
                        </button>
                    ))}
                    <div ref="fontSelect" className={`fontSelect ${!state.fontVisibility && 'hidden'}`}>
                        {fontSize.values.map((v, i) => (
                            <button key={`${fontSize.command}-${v}`} onClick={this.formatFontSize(v)}>
                                <i className="fa fa-fw fa-font" />
                                {fontSize.valueAlias[i]}
                            </button>
                        ))}
                    </div>
                </div>
                <div className="divider" />
                <div className={`linkInput ${!state.linkVisibility && 'hidden'}`}>
                    <div className="left">
                        <div className="item">
                            <label>文字:</label>
                            <input
                                placeholder="链接文字"
                                onChange={this.handleInputChange('linkText')}
                                value={state.linkText}
                            />
                        </div>
                        <div className="item">
                            <label>URL:</label>
                            <input
                                placeholder="URL"
                                onChange={this.handleInputChange('linkValue')}
                                value={state.linkValue}
                            />
                        </div>
                    </div>
                    <button onClick={this.insertLink}>
                        <i className="fa fa-fw fa-check " />
                    </button>
                </div>
                <div
                    ref="editor"
                    className="content"
                    onInput={this.handleInput}
                    onBlur={this.handleBlur}
                    dangerouslySetInnerHTML={{ __html: props.content }}
                />
            </div>
        );
    }
}

Editor.propTypes = {
    content: PropTypes.string,
    style: PropTypes.object,
    onChange: PropTypes.func,
};
